_Pragma("once")

#include <string>
#include <optional>
#include <list>

#include "log.hpp"
#include "libmath.hpp"

#include "lua.hpp"
#include "lauxlib.h"
#include "lualib.h"

namespace sdl_engine::component::script {

class LuaScript {
public:
    LuaScript();
    bool DoFile(const std::string& filename);

    std::optional<double> GetNumber(const std::string& name);
    double GetNumberOrValue(const std::string& name, double defaultValue);
    double GetNumberOrError(const std::string& name);
    bool GetBool(const std::string& name);
    std::string GetString(const std::string& name);
    Color GetColor(const std::string& name);

    bool StartQueryTable(const std::string& tableName);
    void StopQueryTable();

    // for debug
    std::string GetTraceInfo() const;

    // for debug
    int GetTop() const { return lua_gettop(L); }

    ~LuaScript();

private:
    lua_State* L = nullptr;
    std::list<std::string> traceStack_;

    int nest_ = 0; // 0 means the global space

    inline void incNest() { nest_++; }
    inline void decNest() { nest_ = std::max(nest_ -1, 0); }
    inline bool isGlobalSpace() const { return nest_ == 0; }

    std::optional<double> getGlobalNumber(const std::string& name);
    double getGlobalNumberOrValue(const std::string& name, double defaultValue);
    double getGlobalNumberOrError(const std::string& name);
    bool getGlobalBool(const std::string& name);
    std::string getGlobalString(const std::string& name);
    Color getGlobalColor(const std::string& name);

    bool startQueryGlobalTable(const std::string& tableName);
    void stopQueryGlobalTable();

    std::optional<double> getFieldNumber(const std::string& name);
    double getFieldNumberOrError(const std::string& name);
    double getFieldNumberOrValue(const std::string& name, double defaultValue);
    bool getFieldBool(const std::string& name);
    std::string getFieldString(const std::string& name);
    Color getFieldColor(const std::string& name);

    bool startQuerySubTable(const std::string& name);
    void stopQuerySubTable();
};

class LuaBridge final {
public:
    LuaBridge& DoFile(const std::string& filename);

    LuaBridge& Get(double& value, const std::string& name);
    LuaBridge& Get(int& value, const std::string& name);
    LuaBridge& Get(float& value, const std::string& name);
    LuaBridge& Get(std::string& value, const std::string& name);
    LuaBridge& Get(bool& value, const std::string& name);
    LuaBridge& Get(Color& color, const std::string& name);
    LuaBridge& StartTable(const std::string& table);
    LuaBridge& EndTable();

private:
    LuaScript script_;
};

}
